//
//  Crowbar.cpp
//  glmixer
//
//  Created by Ilias Bergstrom on 26/02/13.
//
//

//#include "Crowbar.h"
#include "Crowbar.moc"

#include "RenderingManager.h"

Crowbar::Crowbar() {
    stopped = false;

    m_ReceivingPort    = 5824;
    m_DestinationPort  = 5432;
    m_DestinationIP    = "127.0.0.1";

    readDataFromXML();

    bool success = udpSocket.bind(m_ReceivingPort);
    std::cout <<"BOUND: " << success;

    connect(&udpSocket, SIGNAL(readyRead()),
            this, SLOT(processPendingDatagrams()));

    // Sending a test message

    const int OUTPUT_BUFFER_SIZE = 1024;

    char buffer[OUTPUT_BUFFER_SIZE];

    UdpSocket       socket;
    IpEndpointName  dest(m_DestinationIP.toUtf8().constData(), m_DestinationPort);
    osc::OutboundPacketStream p( buffer, OUTPUT_BUFFER_SIZE);

    p   << osc::BeginBundleImmediate
    << osc::BeginMessage("/testMac1")
    << true << 3423.454f << "helloPC" << osc::EndMessage
    << osc::EndBundle;

    socket.SendTo(dest, p.Data(), p.Size());
}

Crowbar::~Crowbar() {
    udpSocket.close();
}

void Crowbar::processPendingDatagrams() {
    QByteArray datagram;

    do {
        datagram.resize(udpSocket.pendingDatagramSize());
        udpSocket.readDatagram(datagram.data(), datagram.size());
    }
    while (udpSocket.hasPendingDatagrams());

    osc::ReceivedPacket p( datagram.data(), datagram.size() );
    if( p.IsBundle() )
        ProcessBundle( osc::ReceivedBundle(p) );
    else
        ProcessMessage( osc::ReceivedMessage(p) );
}

void Crowbar::ProcessMessage( const osc::ReceivedMessage& m) {
    try {
        const char* ap = m.AddressPattern();
        const char* tts;
        QString qap(ap);
        QStringList fragments = qap.split( QString("/"), QString::SkipEmptyParts);

        if(fragments.count() > 2) {
            if( std::strcmp( fragments[0].toUtf8().constData(), "GLM" ) == 0 ) {

                // Traversing list of sources:
                RenderingManager* rm = RenderingManager::getInstance();

                for ( SourceSet::iterator its = rm->getBegin(); its != rm->getEnd(); its++) {

                    if( std::strcmp( fragments[1].toUtf8().constData(), (*its)->getName().toUtf8().constData() ) == 0 ) {

                        tts = m.TypeTags();

                        fprintf(stderr,
                                "received %s message, tts: %s\n",
                                fragments[2].toUtf8().constData(),
                                tts);

                        ProcessSourceMessage(m, fragments[2], (*its));
                        break;
                    }
                }
            }
        }

//        // Printing list of address pattern fragments:
//        fprintf(stderr, "Fragments: ");
//        for(int i = 0; i < fragments.count(); i++) {
//              fprintf(stderr, "%s, ", fragments[i].toUtf8().constData());
//        }
//        fprintf(stderr, "\n");

//        // Printing list of source names:
//        RenderingManager* rm = RenderingManager::getInstance();

//        fprintf(stderr, "Sources: ");
//        for ( SourceSet::iterator its = rm->getBegin(); its != rm->getEnd(); its++) {
//            fprintf(stderr, "%s, ", (*its)->getName().toUtf8().constData());
//        }
//        fprintf(stderr, "\n");

    }
    catch( osc::Exception& e ) {
        // any parsing errors such as unexpected argument types, or
        // missing arguments get thrown as exceptions.
        fprintf(stderr, "error while parsing message: %s, %s\n", m.AddressPattern(), e.what());
    }
}

void Crowbar::ProcessSourceMessage( const osc::ReceivedMessage& m, QString& message, Source* src ) {
   if( std::strcmp( message.toUtf8().constData(), "Alpha" ) == 0 ) {
        float alpha;
        osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
        alpha   = (arg++)->AsFloat();
        src->setAlpha(alpha);
    }
    else if( std::strcmp( message.toUtf8().constData(), "RotationAngle" ) == 0 ) {
        float val;
        osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
        val   = (arg++)->AsFloat();
        src->setRotationAngle(val);
    }
    else if( std::strcmp( message.toUtf8().constData(), "Brightness" ) == 0 ) {
        int val;
        osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
        val   = (arg++)->AsInt32();
        src->setBrightness(val);
    }
    else if( std::strcmp( message.toUtf8().constData(), "Contrast" ) == 0 ) {
        int val;
        osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
        val   = (arg++)->AsInt32();
        src->setContrast(val);
    }
    else if( std::strcmp( message.toUtf8().constData(), "Saturation" ) == 0 ) {
        int val;
        osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
        val   = (arg++)->AsInt32();
        src->setSaturation(val);
    }
    else if( std::strcmp( message.toUtf8().constData(), "HueShift" ) == 0 ) {
        int val;
        osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
        val   = (arg++)->AsInt32();
        src->setHueShift(val);
    }
    else if( std::strcmp( message.toUtf8().constData(), "ScaleX" ) == 0 ) {
        float val;
        osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
        val   = (arg++)->AsFloat();
        src->setScaleX(val);
    }
    else if( std::strcmp( message.toUtf8().constData(), "ScaleY" ) == 0 ) {
       float val;
       osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
       val   = (arg++)->AsFloat();
       src->setScaleY(val);
   }
}

void Crowbar::ProcessBundle( const osc::ReceivedBundle& b) {
    // ignore bundle time tag for now
    for( osc::ReceivedBundle::const_iterator i = b.ElementsBegin();
            i != b.ElementsEnd(); ++i ){
        if( i->IsBundle() )
            ProcessBundle( osc::ReceivedBundle(*i));
        else
            ProcessMessage( osc::ReceivedMessage(*i));
    }
}

void Crowbar::readDataFromXML() {
    QFile* xmlFile = new QFile("crowbar.xml");

    if (!xmlFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
        QMessageBox::critical(NULL,"Load XML File Problem",
                              "Couldn't open xmlfile.xml to load settings for Crowbar",
                              QMessageBox::Ok);

        return;
    }

    QXmlStreamReader* xmlReader = new QXmlStreamReader(xmlFile);

    //Parse the XML until we reach end of it
    while(!xmlReader->atEnd() && !xmlReader->hasError()) {
        // Read next element
        QXmlStreamReader::TokenType token = xmlReader->readNext();
        //If token is just StartDocument - go to next
        if(token == QXmlStreamReader::StartDocument) {
            continue;
        }
        //If token is StartElement - read it
        if(token == QXmlStreamReader::StartElement) {
            if(xmlReader->name() == "crowbarSettings") {
                int version = xmlReader->attributes().value("fileVersion").toLocal8Bit().toInt();

                if(version == 1) {
                    m_ReceivingPort    = xmlReader->attributes().value("receivingPort").toLocal8Bit().toInt();
                    m_DestinationPort  = xmlReader->attributes().value("destinationPort").toLocal8Bit().toInt();
                    m_DestinationIP    = xmlReader->attributes().value("destinationIP").toString();
                }
            }
        }
    }

    if(xmlReader->hasError()) {
        QMessageBox::critical(NULL,
                              "xmlFile.xml Parse Error",xmlReader->errorString(),
                              QMessageBox::Ok);

        return;
    }

    //close reader and flush file
    xmlReader->clear();
    xmlFile->close();

    delete xmlReader;
    delete xmlFile;
}

